home *** CD-ROM | disk | FTP | other *** search
/ Aminet 2 / Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso / Aminet / util / gnu / groff_src.lha / Groff-1.07 / xditview / draw.c < prev    next >
C/C++ Source or Header  |  1992-12-12  |  15KB  |  721 lines

  1. /*
  2.  * draw.c
  3.  *
  4.  * accept dvi function calls and translate to X
  5.  */
  6.  
  7. #include <X11/Xos.h>
  8. #include <X11/IntrinsicP.h>
  9. #include <X11/StringDefs.h>
  10. #include <stdio.h>
  11. #include <ctype.h>
  12. #include <math.h>
  13.  
  14. /* math.h on a Sequent doesn't define M_PI, apparently */
  15. #ifndef M_PI
  16. #define M_PI    3.14159265358979323846
  17. #endif
  18.  
  19. #include "DviP.h"
  20.  
  21. #define DeviceToX(dw, n) ((int)((n) * (dw)->dvi.scale_factor + .5))
  22. #define XPos(dw) (DeviceToX((dw), (dw)->dvi.state->x - \
  23.                   (dw)->dvi.text_device_width) + (dw)->dvi.text_x_width)
  24. #define YPos(dw) (DeviceToX((dw), (dw)->dvi.state->y))
  25.  
  26. static int FakeCharacter();
  27.  
  28. HorizontalMove(dw, delta)
  29.     DviWidget    dw;
  30.     int        delta;
  31. {
  32.     dw->dvi.state->x += delta;
  33. }
  34.  
  35. HorizontalGoto(dw, NewPosition)
  36.     DviWidget    dw;
  37.     int        NewPosition;
  38. {
  39.     dw->dvi.state->x = NewPosition;
  40. }
  41.  
  42. VerticalMove(dw, delta)
  43.     DviWidget    dw;
  44.     int        delta;
  45. {
  46.     dw->dvi.state->y += delta;
  47. }
  48.  
  49. VerticalGoto(dw, NewPosition)
  50.     DviWidget    dw;
  51.     int        NewPosition;
  52. {
  53.     dw->dvi.state->y = NewPosition;
  54. }
  55.  
  56. AdjustCacheDeltas (dw)
  57.     DviWidget    dw;
  58. {
  59.     int extra;
  60.     int nadj;
  61.     int i;
  62.  
  63.     nadj = 0;
  64.     extra = DeviceToX(dw, dw->dvi.text_device_width)
  65.         - dw->dvi.text_x_width;
  66.     if (extra == 0)
  67.         return;
  68.     for (i = 0; i <= dw->dvi.cache.index; i++)
  69.         if (dw->dvi.cache.adjustable[i])
  70.             ++nadj;
  71.     if (nadj == 0)
  72.         return;
  73.     dw->dvi.text_x_width += extra;
  74.     for (i = 0; i <= dw->dvi.cache.index; i++)
  75.         if (dw->dvi.cache.adjustable[i]) {
  76.             int x;
  77.             int *deltap;
  78.  
  79.             x = extra/nadj;
  80.             deltap = &dw->dvi.cache.cache[i].delta;
  81. #define MIN_DELTA 2
  82.             if (*deltap > 0 && x + *deltap < MIN_DELTA) {
  83.                 x = MIN_DELTA - *deltap;
  84.                 if (x <= 0)
  85.                     *deltap = MIN_DELTA;
  86.                 else
  87.                     x = 0;
  88.             }
  89.             else
  90.                 *deltap += x;
  91.             extra -= x;
  92.             --nadj;
  93.             dw->dvi.cache.adjustable[i] = 0;
  94.         }
  95. }
  96.  
  97. FlushCharCache (dw)
  98.     DviWidget    dw;
  99. {
  100.     if (dw->dvi.cache.char_index != 0) {
  101.         AdjustCacheDeltas (dw);
  102.         XDrawText (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
  103.                dw->dvi.cache.start_x, dw->dvi.cache.start_y,
  104.                dw->dvi.cache.cache, dw->dvi.cache.index + 1);
  105.     }    
  106.     dw->dvi.cache.index = 0;
  107.     dw->dvi.cache.max = DVI_TEXT_CACHE_SIZE;
  108. #if 0
  109.     if (dw->dvi.noPolyText)
  110.         dw->dvi.cache.max = 1;
  111. #endif
  112.     dw->dvi.cache.char_index = 0;
  113.     dw->dvi.cache.cache[0].nchars = 0;
  114.     dw->dvi.cache.start_x = dw->dvi.cache.x    = XPos (dw);
  115.     dw->dvi.cache.start_y = dw->dvi.cache.y = YPos (dw);
  116. }
  117.  
  118. Newline (dw)
  119.     DviWidget    dw;
  120. {
  121.     FlushCharCache (dw);
  122.     dw->dvi.text_x_width = dw->dvi.text_device_width = 0;
  123.     dw->dvi.word_flag = 0;
  124. }
  125.  
  126. Word (dw)
  127.     DviWidget    dw;
  128. {
  129.     dw->dvi.word_flag = 1;
  130. }
  131.  
  132. #define charWidth(fi,c) (\
  133.     (fi)->per_char ?\
  134.     (fi)->per_char[(c) - (fi)->min_char_or_byte2].width\
  135.     :\
  136.     (fi)->max_bounds.width\
  137. )
  138.  
  139.  
  140. static
  141. int charExists (fi, c)
  142.     XFontStruct    *fi;
  143.     int        c;
  144. {
  145.     XCharStruct *p;
  146.  
  147.     if (c < fi->min_char_or_byte2 || c > fi->max_char_or_byte2)
  148.         return 0;
  149.     p = fi->per_char + (c - fi->min_char_or_byte2);
  150.     return (p->lbearing != 0 || p->rbearing != 0 || p->width != 0
  151.         || p->ascent != 0 || p->descent != 0 || p->attributes != 0);
  152. }
  153.  
  154. static
  155. DoCharacter (dw, c, wid)
  156.     DviWidget dw;
  157.     int c;
  158.     int wid;    /* width in device units */
  159. {
  160.     register XFontStruct    *font;
  161.     register XTextItem    *text;
  162.     int    x, y;
  163.     
  164.     x = XPos(dw);
  165.     y = YPos(dw);
  166.  
  167.     /*
  168.      * quick and dirty extents calculation:
  169.      */
  170.     if (!(y + 24 >= dw->dvi.extents.y1
  171.           && y - 24 <= dw->dvi.extents.y2
  172. #if 0
  173.           && x + 24 >= dw->dvi.extents.x1
  174.           && x - 24 <= dw->dvi.extents.x2
  175. #endif
  176.         ))
  177.         return;
  178.     
  179.     if (y != dw->dvi.cache.y
  180.         || dw->dvi.cache.char_index >= DVI_CHAR_CACHE_SIZE) {
  181.         FlushCharCache (dw);
  182.         x = dw->dvi.cache.x;
  183.     }
  184.     /*
  185.      * load a new font, if the current block is not empty,
  186.      * step to the next.
  187.      */
  188.     if (dw->dvi.cache.font_size != dw->dvi.state->font_size ||
  189.         dw->dvi.cache.font_number != dw->dvi.state->font_number)
  190.     {
  191.         dw->dvi.cache.font_size = dw->dvi.state->font_size;
  192.         dw->dvi.cache.font_number = dw->dvi.state->font_number;
  193.         dw->dvi.cache.font = QueryFont (dw,
  194.                         dw->dvi.cache.font_number,
  195.                         dw->dvi.cache.font_size);
  196.         if (dw->dvi.cache.cache[dw->dvi.cache.index].nchars != 0) {
  197.             ++dw->dvi.cache.index;
  198.             if (dw->dvi.cache.index >= dw->dvi.cache.max)
  199.                 FlushCharCache (dw);
  200.             dw->dvi.cache.cache[dw->dvi.cache.index].nchars = 0;
  201.             dw->dvi.cache.adjustable[dw->dvi.cache.index] = 0;
  202.         }
  203.     }
  204.     if (x != dw->dvi.cache.x || dw->dvi.word_flag) {
  205.         if (dw->dvi.cache.cache[dw->dvi.cache.index].nchars != 0) {
  206.             ++dw->dvi.cache.index;
  207.             if (dw->dvi.cache.index >= dw->dvi.cache.max)
  208.                 FlushCharCache (dw);
  209.             dw->dvi.cache.cache[dw->dvi.cache.index].nchars = 0;
  210.         }
  211.         dw->dvi.cache.adjustable[dw->dvi.cache.index]
  212.             = dw->dvi.word_flag;
  213.         dw->dvi.word_flag = 0;
  214.     }
  215.     font = dw->dvi.cache.font;
  216.     text = &dw->dvi.cache.cache[dw->dvi.cache.index];
  217.     if (text->nchars == 0) {
  218.         text->chars = &dw->dvi.cache.char_cache[dw->dvi.cache.char_index];
  219.         text->delta = x - dw->dvi.cache.x;
  220.         if (font != dw->dvi.font) {
  221.             text->font = font->fid;
  222.             dw->dvi.font = font;
  223.         } else
  224.             text->font = None;
  225.         dw->dvi.cache.x += text->delta;
  226.     }
  227.     if (charExists(font, c)) {
  228.         int w;
  229.         dw->dvi.cache.char_cache[dw->dvi.cache.char_index++] = (char) c;
  230.         ++text->nchars;
  231.         w = charWidth(font, c);
  232.         dw->dvi.cache.x += w;
  233.         if (wid != 0) {
  234.             dw->dvi.text_x_width += w;
  235.             dw->dvi.text_device_width += wid;
  236.         }
  237.     }
  238. }
  239.  
  240. static
  241. int FindCharWidth (dw, buf, widp)
  242.     DviWidget dw;
  243.     char *buf;
  244.     int *widp;
  245. {
  246.     int maxpos;
  247.     int i;
  248.  
  249.     if (dw->dvi.device_font == 0
  250.         || dw->dvi.state->font_number != dw->dvi.device_font_number) {
  251.         dw->dvi.device_font_number = dw->dvi.state->font_number;
  252.         dw->dvi.device_font
  253.             = QueryDeviceFont (dw, dw->dvi.device_font_number);
  254.     }
  255.     if (dw->dvi.device_font
  256.         && device_char_width (dw->dvi.device_font,
  257.                   dw->dvi.state->font_size, buf, widp))
  258.         return 1;
  259.  
  260.     maxpos = MaxFontPosition (dw);
  261.     for (i = 1; i <= maxpos; i++) {
  262.         DeviceFont *f = QueryDeviceFont (dw, i);
  263.         if (f && device_font_special (f)
  264.             && device_char_width (f, dw->dvi.state->font_size,
  265.                       buf, widp)) {
  266.             dw->dvi.state->font_number = i;
  267.             return 1;
  268.         }
  269.     }
  270.     return 0;
  271. }
  272.  
  273. /* Return the width of the character in device units. */
  274.  
  275. int PutCharacter (dw, buf)
  276.     DviWidget dw;
  277.     char *buf;
  278. {
  279.     int        prevFont;
  280.     int        c = -1;
  281.     int        wid = 0;
  282.     DviCharNameMap    *map;
  283.  
  284.     if (!dw->dvi.display_enable)
  285.         return 0;    /* The width doesn't matter in this case. */
  286.     prevFont = dw->dvi.state->font_number;
  287.     if (!FindCharWidth (dw, buf, &wid))
  288.         return 0;
  289.     map = QueryFontMap (dw, dw->dvi.state->font_number);
  290.     if (map)
  291.         c = DviCharIndex (map, buf);
  292.     if (c >= 0)
  293.         DoCharacter (dw, c, wid);
  294.     else
  295.         (void) FakeCharacter (dw, buf, wid);
  296.     dw->dvi.state->font_number = prevFont;
  297.     return wid;
  298. }
  299.  
  300. /* Return 1 if we can fake it; 0 otherwise. */
  301.  
  302. static
  303. int FakeCharacter (dw, buf, wid)
  304.     DviWidget dw;
  305.     char *buf;
  306.     int wid;
  307. {
  308.     int oldx, oldw;
  309.     char ch[2];
  310.     char *chars = 0;
  311.  
  312.     if (buf[0] == '\0' || buf[1] == '\0' || buf[2] != '\0')
  313.         return 0;
  314. #define pack2(c1, c2) (((c1) << 8) | (c2))
  315.  
  316.     switch (pack2(buf[0], buf[1])) {
  317.     case pack2('f', 'i'):
  318.         chars = "fi";
  319.         break;
  320.     case pack2('f', 'l'):
  321.         chars = "fl";
  322.         break;
  323.     case pack2('f', 'f'):
  324.         chars = "ff";
  325.         break;
  326.     case pack2('F', 'i'):
  327.         chars = "ffi";
  328.         break;
  329.     case pack2('F', 'l'):
  330.         chars = "ffl";
  331.         break;
  332.     }
  333.     if (!chars)
  334.         return 0;
  335.     oldx = dw->dvi.state->x;
  336.     oldw = dw->dvi.text_device_width;
  337.     ch[1] = '\0';
  338.     for (; *chars; chars++) {
  339.         ch[0] = *chars;
  340.         dw->dvi.state->x += PutCharacter (dw, ch);
  341.     }
  342.     dw->dvi.state->x = oldx;
  343.     dw->dvi.text_device_width = oldw + wid;
  344.     return 1;
  345. }
  346.  
  347. PutNumberedCharacter (dw, c)
  348.     DviWidget dw;
  349.     int c;
  350. {
  351.     char *name;
  352.     int wid;
  353.     DviCharNameMap    *map;
  354.  
  355.     if (!dw->dvi.display_enable)
  356.         return;
  357.  
  358.     if (dw->dvi.device_font == 0
  359.         || dw->dvi.state->font_number != dw->dvi.device_font_number) {
  360.         dw->dvi.device_font_number = dw->dvi.state->font_number;
  361.         dw->dvi.device_font
  362.             = QueryDeviceFont (dw, dw->dvi.device_font_number);
  363.     }
  364.     
  365.     if (dw->dvi.device_font == 0
  366.         || !device_code_width (dw->dvi.device_font,
  367.                    dw->dvi.state->font_size, c, &wid))
  368.         return;
  369.     if (dw->dvi.native) {
  370.         DoCharacter (dw, c, wid);
  371.         return;
  372.     }
  373.     map = QueryFontMap (dw, dw->dvi.state->font_number);
  374.     if (!map)
  375.         return;
  376.     for (name = device_name_for_code (dw->dvi.device_font, c);
  377.          name;
  378.          name = device_name_for_code ((DeviceFont *)0, c)) {
  379.         int code = DviCharIndex (map, name);
  380.         if (code >= 0) {
  381.             DoCharacter (dw, code, wid);
  382.             break;
  383.         }
  384.         if (FakeCharacter (dw, name, wid))
  385.             break;
  386.     }
  387. }
  388.  
  389. ClearPage (dw)
  390.     DviWidget    dw;
  391. {
  392.     XClearWindow (XtDisplay (dw), XtWindow (dw));
  393. }
  394.  
  395. static
  396. setGC (dw)
  397.     DviWidget    dw;
  398. {
  399.     int desired_line_width;
  400.     
  401.     if (dw->dvi.line_thickness < 0)
  402.         desired_line_width = (int)(((double)dw->dvi.device_resolution
  403.                         * dw->dvi.state->font_size)
  404.                        / (10.0*72.0*dw->dvi.sizescale));
  405.     else
  406.         desired_line_width = dw->dvi.line_thickness;
  407.     
  408.     if (desired_line_width != dw->dvi.line_width) {
  409.         XGCValues values;
  410.         values.line_width = DeviceToX(dw, desired_line_width);
  411.         if (values.line_width == 0)
  412.             values.line_width = 1;
  413.         XChangeGC(XtDisplay (dw), dw->dvi.normal_GC,
  414.               GCLineWidth, &values);
  415.         dw->dvi.line_width = desired_line_width;
  416.     }
  417. }
  418.  
  419. static
  420. setFillGC (dw)
  421.     DviWidget    dw;
  422. {
  423.     int fill_type;
  424.     
  425.     if (dw->dvi.fill == DVI_FILL_MAX)
  426.         fill_type = DVI_FILL_BLACK;
  427.     else if (dw->dvi.fill == 0)
  428.         fill_type = DVI_FILL_WHITE;
  429.     else
  430.         fill_type = DVI_FILL_GRAY;
  431.     if (dw->dvi.fill_type != fill_type) {
  432.         XGCValues values;
  433.         switch (fill_type) {
  434.         case DVI_FILL_WHITE:
  435.             values.foreground = dw->dvi.background;
  436.             values.fill_style = FillSolid;
  437.             break;
  438.         case DVI_FILL_BLACK:
  439.             values.foreground = dw->dvi.foreground;
  440.             values.fill_style = FillSolid;
  441.             break;
  442.         case DVI_FILL_GRAY:
  443.             values.foreground = dw->dvi.foreground;
  444.             values.fill_style = FillOpaqueStippled;
  445.             break;
  446.         }
  447.         XChangeGC(XtDisplay (dw), dw->dvi.fill_GC,
  448.               GCFillStyle|GCForeground,
  449.               &values);
  450.         dw->dvi.fill_type = fill_type;
  451.     }
  452. }
  453.  
  454. DrawLine (dw, x, y)
  455.     DviWidget    dw;
  456.     int        x, y;
  457. {
  458.     int xp, yp;
  459.  
  460.     AdjustCacheDeltas (dw);
  461.     setGC (dw);
  462.     xp = XPos (dw);
  463.     yp = YPos (dw);
  464.     XDrawLine (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
  465.            xp, yp,
  466.            xp + DeviceToX (dw, x), yp + DeviceToX (dw, y));
  467. }
  468.  
  469. DrawCircle (dw, diam)
  470.     DviWidget    dw;
  471.     int        diam;
  472. {
  473.     int d;
  474.  
  475.     AdjustCacheDeltas (dw);
  476.     setGC (dw);
  477.     d = DeviceToX (dw, diam);
  478.     XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
  479.           XPos (dw), YPos (dw) - d/2,
  480.           d, d, 0, 64*360);
  481. }
  482.  
  483. DrawFilledCircle (dw, diam)
  484.     DviWidget    dw;
  485.     int        diam;
  486. {
  487.     int d;
  488.  
  489.     AdjustCacheDeltas (dw);
  490.     setFillGC (dw);
  491.     d = DeviceToX (dw, diam);
  492.     XFillArc (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
  493.           XPos (dw), YPos (dw) - d/2,
  494.           d, d, 0, 64*360);
  495. }
  496.  
  497. DrawEllipse (dw, a, b)
  498.     DviWidget    dw;
  499.     int        a, b;
  500. {
  501.     AdjustCacheDeltas (dw);
  502.     setGC (dw);
  503.     XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
  504.           XPos (dw), YPos (dw) - DeviceToX (dw, b/2),
  505.           DeviceToX (dw, a), DeviceToX (dw, b), 0, 64*360);
  506. }
  507.  
  508. DrawFilledEllipse (dw, a, b)
  509.     DviWidget    dw;
  510.     int        a, b;
  511. {
  512.     AdjustCacheDeltas (dw);
  513.     setFillGC (dw);
  514.     XFillArc (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
  515.           XPos (dw), YPos (dw) - DeviceToX (dw, b/2),
  516.           DeviceToX (dw, a), DeviceToX (dw, b), 0, 64*360);
  517. }
  518.  
  519. DrawArc (dw, x0, y0, x1, y1)
  520.     DviWidget    dw;
  521.     int        x0, y0, x1, y1;
  522. {
  523.     int angle1, angle2;
  524.     int rad = (int)((sqrt ((double)x0*x0 + (double)y0*y0)
  525.             + sqrt ((double)x1*x1 + (double)y1*y1) + 1.0)/2.0);
  526.     if ((x0 == 0 && y0 == 0) || (x1 == 0 && y1 == 0))
  527.         return;
  528.     angle1 = (int)(atan2 ((double)y0, (double)-x0)*180.0*64.0/M_PI);
  529.     angle2 = (int)(atan2 ((double)-y1, (double)x1)*180.0*64.0/M_PI);
  530.     
  531.     angle2 -= angle1;
  532.     if (angle2 < 0)
  533.         angle2 += 64*360;
  534.     
  535.     AdjustCacheDeltas (dw);
  536.     setGC (dw);
  537.  
  538.     rad = DeviceToX (dw, rad);
  539.     XDrawArc (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
  540.           XPos (dw) + DeviceToX (dw, x0) - rad,
  541.           YPos (dw) + DeviceToX (dw, y0) - rad,
  542.           rad*2, rad*2, angle1, angle2);
  543. }
  544.  
  545. DrawPolygon (dw, v, n)
  546.     DviWidget    dw;
  547.     int        *v;
  548.     int        n;
  549. {
  550.     XPoint *p;
  551.     int i;
  552.     int dx, dy;
  553.     
  554.     n /= 2;
  555.     
  556.     AdjustCacheDeltas (dw);
  557.     setGC (dw);
  558.     p = (XPoint *)XtMalloc((n + 2)*sizeof(XPoint));
  559.     p[0].x = XPos (dw);
  560.     p[0].y = YPos (dw);
  561.     dx = 0;
  562.     dy = 0;
  563.     for (i = 0; i < n; i++) {
  564.         dx += v[2*i];
  565.         p[i + 1].x = DeviceToX (dw, dx) + p[0].x;
  566.         dy += v[2*i + 1];
  567.         p[i + 1].y = DeviceToX (dw, dy) + p[0].y;
  568.     }
  569.     p[n+1].x = p[0].x;
  570.     p[n+1].y = p[0].y;
  571.     XDrawLines (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
  572.            p, n + 2, CoordModeOrigin);
  573.     XtFree((char *)p);
  574. }
  575.  
  576.  
  577. DrawFilledPolygon (dw, v, n)
  578.     DviWidget    dw;
  579.     int        *v;
  580.     int        n;
  581. {
  582.     XPoint *p;
  583.     int i;
  584.     int dx, dy;
  585.     
  586.     n /= 2;
  587.     if (n < 2)
  588.         return;
  589.     
  590.     AdjustCacheDeltas (dw);
  591.     setFillGC (dw);
  592.     p = (XPoint *)XtMalloc((n + 1)*sizeof(XPoint));
  593.     p[0].x = XPos (dw);
  594.     p[0].y = YPos (dw);
  595.     dx = 0;
  596.     dy = 0;
  597.     for (i = 0; i < n; i++) {
  598.         dx += v[2*i];
  599.         p[i + 1].x = DeviceToX (dw, dx) + p[0].x;
  600.         dy += v[2*i + 1];
  601.         p[i + 1].y = DeviceToX (dw, dy) + p[0].y;
  602.     }
  603.     XFillPolygon (XtDisplay (dw), XtWindow (dw), dw->dvi.fill_GC,
  604.               p, n + 1, Complex, CoordModeOrigin);
  605.     XtFree((char *)p);
  606. }
  607.  
  608. #define POINTS_MAX 10000
  609.  
  610. static
  611. appendPoint(points, pointi, x, y)
  612.     XPoint    *points;
  613.     int    *pointi;
  614.     int    x, y;
  615. {
  616.     if (*pointi < POINTS_MAX) {
  617.         points[*pointi].x = x;
  618.         points[*pointi].y = y;
  619.         *pointi += 1;
  620.     }
  621. }
  622.  
  623. #define FLATNESS 1
  624.  
  625. static
  626. flattenCurve(points, pointi, x2, y2, x3, y3, x4, y4)
  627.     XPoint    *points;
  628.     int    *pointi;
  629.     int    x2, y2, x3, y3, x4, y4;
  630. {
  631.     int x1, y1, dx, dy, n1, n2, n;
  632.  
  633.     x1 = points[*pointi - 1].x;
  634.     y1 = points[*pointi - 1].y;
  635.     
  636.     dx = x4 - x1;
  637.     dy = y4 - y1;
  638.     
  639.     n1 = dy*(x2 - x1) - dx*(y2 - y1);
  640.     n2 = dy*(x3 - x1) - dx*(y3 - y1);
  641.     if (n1 < 0)
  642.         n1 = -n1;
  643.     if (n2 < 0)
  644.         n2 = -n2;
  645.     n = n1 > n2 ? n1 : n2;
  646.  
  647.     if (n*n / (dy*dy + dx*dx) <= FLATNESS*FLATNESS)
  648.         appendPoint (points, pointi, x4, y4);
  649.     else {
  650.         flattenCurve (points, pointi,
  651.                   (x1 + x2)/2, (y1 + y2)/2,
  652.                   (x1 + x2*2 + x3)/4, (y1 + y2*2 + y3)/4,
  653.                   (x1 +3*x2 + 3*x3 + x4)/8, (y1 +3*y2 + 3*y3 + y4)/8);
  654.         flattenCurve (points, pointi,
  655.                   (x2 + x3*2 + x4)/4, (y2 + y3*2 + y4)/4,
  656.                   (x3 + x4)/2, (y3 + y4)/2,
  657.                   x4, y4);
  658.     }
  659. }
  660.  
  661.  
  662. DrawSpline (dw, v, n)
  663.     DviWidget    dw;
  664.     int        *v;
  665.     int        n;
  666. {
  667.     int sx, sy, tx, ty;
  668.     int ox, oy, dx, dy;
  669.     int i;
  670.     int pointi;
  671.     XPoint points[POINTS_MAX];
  672.     
  673.     if (n == 0 || (n & 1) != 0)
  674.         return;
  675.     AdjustCacheDeltas (dw);
  676.     setGC (dw);
  677.     ox = XPos (dw);
  678.     oy = YPos (dw);
  679.     dx = v[0];
  680.     dy = v[1];
  681.     sx = ox;
  682.     sy = oy;
  683.     tx = sx + DeviceToX (dw, dx);
  684.     ty = sy + DeviceToX (dw, dy);
  685.     
  686.     pointi = 0;
  687.     
  688.     appendPoint (points, &pointi, sx, sy);
  689.     appendPoint (points, &pointi, (sx + tx)/2, (sy + ty)/2);
  690.     
  691.     for (i = 2; i < n; i += 2) {
  692.         int ux = ox + DeviceToX (dw, dx += v[i]);
  693.         int uy = oy + DeviceToX (dw, dy += v[i+1]);
  694.         flattenCurve (points, &pointi,
  695.                    (sx + tx*5)/6, (sy + ty*5)/6,
  696.                    (tx*5 + ux)/6, (ty*5 + uy)/6,
  697.                    (tx + ux)/2, (ty + uy)/2);
  698.         sx = tx;
  699.         sy = ty;
  700.         tx = ux;
  701.         ty = uy;
  702.     }
  703.     
  704.     appendPoint (points, &pointi, tx, ty);
  705.     
  706.     XDrawLines (XtDisplay (dw), XtWindow (dw), dw->dvi.normal_GC,
  707.            points, pointi, CoordModeOrigin);
  708. }
  709.  
  710.  
  711. /*
  712. Local Variables:
  713. c-indent-level: 8
  714. c-continued-statement-offset: 8
  715. c-brace-offset: -8
  716. c-argdecl-indent: 8
  717. c-label-offset: -8
  718. c-tab-always-indent: nil
  719. End:
  720. */
  721.